/**
 * 文件上传工具
 * 支持获取签名并直传MinIO
 */
import { picker } from '@kit.CoreFileKit'
import { request } from '@kit.BasicServicesKit'
import type { UploadSignResponse, UploadResult } from '../models/Upload'
import { BusinessError } from '@kit.BasicServicesKit'
import { common } from '@kit.AbilityKit'
import { fileIo, fileUri } from '@kit.CoreFileKit'

/**
 * 选择图片文件
 * @returns 返回文件URI
 */
export async function selectImage(): Promise<string | null> {
  try {
    const photoSelectOptions = new picker.PhotoSelectOptions()
    photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE
    photoSelectOptions.maxSelectNumber = 1

    const photoPicker = new picker.PhotoViewPicker()
    const photoSelectResult = await photoPicker.select(photoSelectOptions)

    if (photoSelectResult && photoSelectResult.photoUris && photoSelectResult.photoUris.length > 0) {
      return photoSelectResult.photoUris[0]
    }
    return null
  } catch (err) {
    console.error('选择图片失败:', err)
    return null
  }
}

/**
 * 文件信息接口
 */
export interface FileInfo {
  uri: string
  fileName: string
  fileSize: number
  fileType: string
}

/**
 * 选择文档文件（支持pdf, doc, docx等）
 * @returns 返回文件信息
 */
export async function selectDocument(): Promise<FileInfo | null> {
  try {
    const documentSelectOptions = new picker.DocumentSelectOptions()
    const documentPicker = new picker.DocumentViewPicker()
    const documentSelectResult = await documentPicker.select(documentSelectOptions)

    if (documentSelectResult && documentSelectResult.length > 0) {
      const fileUri = documentSelectResult[0]
      
      // 获取文件名
      const fileName = fileUri.substring(fileUri.lastIndexOf('/') + 1)
      
      // 获取文件扩展名
      const fileExt = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase()
      
      // 获取文件大小
      let fileSize = 0
      try {
        const stat = fileIo.statSync(fileUri)
        fileSize = stat.size
        console.log('[selectDocument] 文件大小:', fileSize, 'bytes')
      } catch (err) {
        console.error('[selectDocument] 获取文件大小失败:', err)
        // 如果 statSync 失败，尝试通过读取文件来获取大小
        try {
          const file = fileIo.openSync(fileUri, fileIo.OpenMode.READ_ONLY)
          // 读取整个文件来获取大小
          const buffer = new ArrayBuffer(1024 * 1024 * 10) // 10MB buffer
          let totalSize = 0
          let readSize = 0
          while ((readSize = fileIo.readSync(file.fd, buffer)) > 0) {
            totalSize += readSize
          }
          fileIo.closeSync(file)
          fileSize = totalSize
          console.log('[selectDocument] 通过读取获取文件大小:', fileSize, 'bytes')
        } catch (err2) {
          console.error('[selectDocument] 读取文件失败:', err2)
        }
      }
      
      return {
        uri: fileUri,
        fileName: fileName,
        fileSize: fileSize,
        fileType: fileExt
      }
    }
    return null
  } catch (err) {
    console.error('选择文档失败:', err)
    return null
  }
}

/**
 * 选择多张图片文件
 * @param maxCount 最大选择数量
 * @returns 返回文件URI数组
 */
export async function selectImages(maxCount: number): Promise<string[]> {
  try {
    const photoSelectOptions = new picker.PhotoSelectOptions()
    photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE
    photoSelectOptions.maxSelectNumber = maxCount

    const photoViewPicker = new picker.PhotoViewPicker()
    const photoSelectResult = await photoViewPicker.select(photoSelectOptions)

    if (photoSelectResult && photoSelectResult.photoUris && photoSelectResult.photoUris.length > 0) {
      return photoSelectResult.photoUris
    }
    return []
  } catch (err) {
    console.error('选择图片失败:', err)
    return []
  }
}

/**
 * 将用户文件复制到应用沙箱
 * @param sourceUri 源文件URI（如相册图片）
 * @param context 应用上下文
 * @returns 沙箱路径
 */
async function copyToSandbox(sourceUri: string, context: common.UIAbilityContext): Promise<string> {
  try {
    // 将URI转换为路径
    const srcPath = fileUri.getUriFromPath(sourceUri)
    
    // 生成沙箱目标路径
    const fileName = `upload_${Date.now()}.jpg`
    const destPath = `${context.cacheDir}/${fileName}`
    
    console.log('复制文件:', sourceUri, '->', destPath)
    
    // 打开源文件
    const srcFile = fileIo.openSync(sourceUri, fileIo.OpenMode.READ_ONLY)
    // 创建目标文件
    const destFile = fileIo.openSync(destPath, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE)
    
    // 复制文件内容
    const bufferSize = 4096
    const buffer = new ArrayBuffer(bufferSize)
    let readSize = 0
    while ((readSize = fileIo.readSync(srcFile.fd, buffer)) > 0) {
      fileIo.writeSync(destFile.fd, buffer, { length: readSize })
    }
    
    // 关闭文件
    fileIo.closeSync(srcFile)
    fileIo.closeSync(destFile)
    
    console.log('文件复制成功:', destPath)
    return destPath
  } catch (err) {
    console.error('复制文件到沙箱失败:', err)
    throw err
  }
}

/**
 * 上传文件到MinIO（使用request.agent）
 * @param userFileUri 用户文件URI（如相册图片）
 * @param getSignFunc 获取签名的函数
 * @param context 应用上下文
 * @param showLoading 是否显示loading动画，默认为true
 * @returns 上传结果，包含accessPath
 */
export async function uploadToMinIO(
  userFileUri: string,
  getSignFunc: (showLoading?: boolean) => Promise<UploadSignResponse>,
  context: common.UIAbilityContext,
  showLoading: boolean = true
): Promise<UploadResult> {
  let sandboxPath: string | null = null
  try {
    // 1. 将用户文件复制到沙箱
    sandboxPath = await copyToSandbox(userFileUri, context)
    
    // 2. 获取上传签名
    const signData: UploadSignResponse = await getSignFunc(showLoading)
    console.log('获取签名成功:', JSON.stringify(signData))
    console.log('准备上传文件:', sandboxPath)

    // 3. 构造表单数据（签名字段 + 文件）
    const formData: Array<request.agent.FormItem> = []
    
    // 添加签名字段
    Object.keys(signData.formData).forEach((key: string) => {
      formData.push({
        name: key,
        value: (signData.formData as any)[key]
      })
    })
    
    // 添加文件字段（使用沙箱路径）
    formData.push({
      name: 'file',
      value: {
        filename: signData.objectName.split('/').pop() || 'file.jpg',
        mimeType: 'image/*',
        path: sandboxPath
      }
    })

    // 3. 配置上传任务
    const uploadConfig: request.agent.Config = {
      action: request.agent.Action.UPLOAD,
      url: signData.url,
      method: 'POST',
      mode: request.agent.Mode.FOREGROUND,
      title: '上传图片',
      data: formData,
      network: request.agent.Network.ANY,
      index: 0,
      begins: 0,
      ends: -1,
      overwrite: false,
      retry: true,
      redirect: true,
      gauge: false
    }

    // 4. 创建上传任务
    console.log('创建上传任务...')
    const task = await request.agent.create(context, uploadConfig)
    console.log('上传任务已创建')

    // 5. 监听上传进度和结果
    return new Promise<UploadResult>((resolve) => {
      // 监听上传完成
      task.on('completed', (progress: request.agent.Progress) => {
        console.log('上传完成:', JSON.stringify(progress))
        // MinIO上传成功，使用签名中的accessPath
        task.off('completed')
        task.off('failed')
        request.agent.remove(task.tid).then(() => {
          console.log('上传任务已清理')
        })
        // 清理沙箱临时文件
        if (sandboxPath) {
          try {
            fileIo.unlinkSync(sandboxPath)
            console.log('沙箱临时文件已删除:', sandboxPath)
          } catch (err) {
            console.error('删除沙箱文件失败:', err)
          }
        }
        resolve({
          success: true,
          accessPath: signData.accessPath
        })
      })

      // 监听上传失败
      task.on('failed', (progress: request.agent.Progress) => {
        console.error('上传失败:', JSON.stringify(progress))
        task.off('completed')
        task.off('failed')
        request.agent.remove(task.tid).then(() => {
          console.log('上传任务已清理')
        })
        // 清理沙箱临时文件
        if (sandboxPath) {
          try {
            fileIo.unlinkSync(sandboxPath)
            console.log('沙箱临时文件已删除:', sandboxPath)
          } catch (err) {
            console.error('删除沙箱文件失败:', err)
          }
        }
        resolve({
          success: false,
          error: `上传失败: ${progress.extras?.['failedReason'] || '未知错误'}`
        })
      })
      
      // 启动上传
      task.start().then(() => {
        console.log('上传任务已启动')
      }).catch((err: BusinessError) => {
        console.error('启动上传失败:', err)
        resolve({
          success: false,
          error: err.message || '启动上传失败'
        })
      })
    })
  } catch (err) {
    console.error('上传文件失败:', err)
    const error = err as BusinessError
    return {
      success: false,
      error: error.message || '上传失败'
    }
  }
}

/**
 * 选择并上传图片
 * @param getSignFunc 获取签名的函数
 * @param context 应用上下文
 * @returns 上传结果，包含accessPath
 */
export async function selectAndUploadImage(
  getSignFunc: () => Promise<UploadSignResponse>,
  context: common.UIAbilityContext
): Promise<UploadResult> {
  // 1. 选择图片
  const fileUri = await selectImage()
  if (!fileUri) {
    return {
      success: false,
      error: '未选择图片'
    }
  }

  // 2. 上传图片
  return await uploadToMinIO(fileUri, getSignFunc, context)
}

/**
 * 批量上传结果
 */
export interface BatchUploadResult {
  success: boolean
  uploadedPaths: string[]  // 成功上传的图片路径
  failedCount: number      // 失败的数量
  error?: string
}

/**
 * 批量上传图片到MinIO
 * @param userFileUris 用户文件URI数组
 * @param signDataList 签名数据列表
 * @param context 应用上下文
 * @returns 批量上传结果
 */
export async function batchUploadToMinIO(
  userFileUris: string[],
  signDataList: UploadSignResponse[],
  context: common.UIAbilityContext
): Promise<BatchUploadResult> {
  const uploadedPaths: string[] = []
  let failedCount = 0

  // 逐个上传
  for (let i = 0; i < userFileUris.length && i < signDataList.length; i++) {
    try {
      const fileUri = userFileUris[i]
      const signData = signDataList[i]
      
      // 复制到沙箱
      const sandboxPath = await copyToSandbox(fileUri, context)
      
      // 构造表单数据
      const formData: Array<request.agent.FormItem> = []
      
      // 添加签名字段
      Object.keys(signData.formData).forEach((key: string) => {
        formData.push({
          name: key,
          value: (signData.formData as any)[key]
        })
      })
      
      // 添加文件字段
      formData.push({
        name: 'file',
        value: {
          filename: signData.objectName.split('/').pop() || 'file.jpg',
          mimeType: 'image/*',
          path: sandboxPath
        }
      })

      // 配置上传任务
      const uploadConfig: request.agent.Config = {
        action: request.agent.Action.UPLOAD,
        url: signData.url,
        method: 'POST',
        mode: request.agent.Mode.FOREGROUND,
        title: `上传图片 ${i + 1}/${userFileUris.length}`,
        data: formData,
        network: request.agent.Network.ANY,
        index: 0,
        begins: 0,
        ends: -1,
        overwrite: false,
        retry: true,
        redirect: true,
        gauge: false
      }

      // 创建并执行上传任务
      const task = await request.agent.create(context, uploadConfig)
      
      const uploadSuccess = await new Promise<boolean>((resolve) => {
        task.on('completed', (progress: request.agent.Progress) => {
          console.log(`图片 ${i + 1} 上传完成`)
          task.off('completed')
          task.off('failed')
          request.agent.remove(task.tid)
          // 清理沙箱文件
          try {
            fileIo.unlinkSync(sandboxPath)
          } catch (err) {
            console.error('删除沙箱文件失败:', err)
          }
          resolve(true)
        })

        task.on('failed', (progress: request.agent.Progress) => {
          console.error(`图片 ${i + 1} 上传失败:`, progress)
          task.off('completed')
          task.off('failed')
          request.agent.remove(task.tid)
          // 清理沙箱文件
          try {
            fileIo.unlinkSync(sandboxPath)
          } catch (err) {
            console.error('删除沙箱文件失败:', err)
          }
          resolve(false)
        })
        
        task.start().catch((err: BusinessError) => {
          console.error(`启动图片 ${i + 1} 上传失败:`, err)
          resolve(false)
        })
      })

      if (uploadSuccess) {
        uploadedPaths.push(signData.accessPath)
      } else {
        failedCount++
      }
    } catch (err) {
      console.error(`处理图片 ${i + 1} 失败:`, err)
      failedCount++
    }
  }

  return {
    success: uploadedPaths.length > 0,
    uploadedPaths,
    failedCount
  }
}

/**
 * 选择并批量上传图片
 * @param maxCount 最大选择数量
 * @param getBatchSignFunc 批量获取签名的函数
 * @param context 应用上下文
 * @returns 批量上传结果
 */
export async function selectAndBatchUploadImages(
  maxCount: number,
  getBatchSignFunc: (count: number) => Promise<UploadSignResponse[]>,
  context: common.UIAbilityContext
): Promise<BatchUploadResult> {
  // 1. 选择图片
  const fileUris = await selectImages(maxCount)
  if (fileUris.length === 0) {
    return {
      success: false,
      uploadedPaths: [],
      failedCount: 0,
      error: '未选择图片'
    }
  }

  // 2. 获取签名
  try {
    const signDataList = await getBatchSignFunc(fileUris.length)
    
    // 3. 批量上传
    return await batchUploadToMinIO(fileUris, signDataList, context)
  } catch (err) {
    console.error('批量上传失败:', err)
    return {
      success: false,
      uploadedPaths: [],
      failedCount: fileUris.length,
      error: '获取上传签名失败'
    }
  }
}
